package com.nullpointer.xchat.service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;

import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.media.RingtoneManager;
import android.net.ConnectivityManager;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.telephony.TelephonyManager;
import android.widget.ImageView;

import com.androidquery.AQuery;
import com.androidquery.callback.AjaxStatus;
import com.androidquery.callback.BitmapAjaxCallback;
import com.nullpointer.xchat.MainActivity;
import com.nullpointer.xchat.R;
import com.nullpointer.xchat.database.MessagesDataManager;
import com.nullpointer.xchat.object.AutoChatResponse;
import com.nullpointer.xchat.object.MessageContent;
import com.nullpointer.xchat.object.MessageContent.MsgType;
import com.nullpointer.xchat.object.User;
import com.nullpointer.xchat.object.UserInfo;
import com.nullpointer.xchat.service.NetworkReceiver.OnNetworkListener;
import com.nullpointer.xchat.task.DefaultGetTask;
import com.nullpointer.xchat.task.DefaultGetTask.onGetTaskListener;
import com.nullpointer.xchat.utils.Common;
import com.nullpointer.xchat.utils.DataManager;
import com.nullpointer.xchat.utils.KiraGameLog;
import com.nullpointer.xchat.utils.Utils;
import com.quickblox.core.QBCallback;
import com.quickblox.core.QBCallbackImpl;
import com.quickblox.core.QBSettings;
import com.quickblox.core.result.Result;
import com.quickblox.internal.core.request.QBPagedRequestBuilder;
import com.quickblox.module.auth.QBAuth;
import com.quickblox.module.chat.QBChatRoom;
import com.quickblox.module.chat.QBChatService;
import com.quickblox.module.chat.listeners.ChatMessageListener;
import com.quickblox.module.chat.listeners.RoomListener;
import com.quickblox.module.chat.listeners.SessionCallback;
import com.quickblox.module.chat.smack.SmackAndroid;
import com.quickblox.module.chat.xmpp.QBPrivateChat;
import com.quickblox.module.users.QBUsers;
import com.quickblox.module.users.model.QBUser;
import com.quickblox.module.users.result.QBUserPagedResult;

public class ChatService extends Service implements RoomListener {

	// UI Name
	public static final String UI_NAME_LOGIN = "UI_NAME_LOGIN";
	public static final String UI_NAME_MAIN = "UI_NAME_MAIN";
	public static final String UI_NAME_CHAT_PRIVATE = "UI_NAME_CHAT_PRIVATE";

	// BROADCAST NAME
	public static final String BROADCAST_NAME_LOGIN = "com.kiragame.xchat.changeuilogin";
	public static final String BROADCAST_NAME_MAIN = "com.kiragame.xchat.changeuimain";
	public static final String BROADCAST_NAME_CHAT_PRIVATE = "com.kiragame.xchat.changeuichatprivate";

	// COMMON CONTROL
	public static final String CONTROL_MESSAGE = "CONTROL_MESSAGE";
	public static final String CONTROL_ACTION = "CONTROL_ACTION";

	// ACTION UI LOGIN
	public static final String LOGIN_ACTION_HIDE_PROGESSBAR = "ACTION_HIDE_PROGESSBAR";
	public static final String LOGIN_ACTION_SHOW_PROGESSBAR = "ACTION_SHOW_PROGESSBAR";
	public static final String LOGIN_ACTION_SHOW_NOTICE = "ACTION_SHOW_NOTICE";
	public static final String LOGIN_ACTION_GO_TO_ROOM = "ACTION_GO_TO_ROOM";

	// ACTION UI MAIN
	public static final String MAIN_ACTION_NOTIFY_CONNECTION_ONLINE = "MAIN_ACTION_NOTIFY_CONNECTION_ONLINE";
	public static final String MAIN_ACTION_NOTIFY_CONNECTION_OFFLINE = "MAIN_ACTION_NOTIFY_CONNECTION_OFFLINE";

	public static final String MAIN_ACTION_UPDATE_MESSAGES_IN_CHAT_ROOM_FRAGMENT = "MAIN_ACTION_UPDATE_MESSAGES_IN_CHAT_ROOM_FRAGMENT";
	public static final String MAIN_ACTION_UPDATE_MESSAGES_IN_MESSAGE_FRAGMENT = "MAIN_ACTION_UPDATE_MESSAGES_IN_MESSAGE_FRAGMENT";

	public static final String MAIN_ACTION_ON_PRE_SETUP_SERVER = "MAIN_ACTION_ON_PRE_SETUP_SEVER";
	public static final String MAIN_ACTION_ON_FINISHED_SETUP_SERVER = "MAIN_ACTION_ON_FINISHED_SETUP_SERVER";

	public static final String MAIN_ACTION_ON_PRE_UPDATE_PROFILE = "MAIN_ACTION_ON_PRE_UPDATE_PROFILE";
	public static final String MAIN_ACTION_ON_FINISHED_UPDATE_PROFILE = "MAIN_ACTION_ON_FINISHED_UPDATE_PROFILE";

	public static final String MAIN_ACTION_ON_PRE_JOIN_ROOM = "MAIN_ACTION_ON_PRE_JOIN_ROOM";
	public static final String MAIN_ACTION_ON_FINISHED_JOIN_ROOM = "MAIN_ACTION_ON_FINISHED_JOIN_ROOM";

	public static final String MAIN_ACTION_ON_PRE_GET_ROOM_USERS = "MAIN_ACTION_ON_PRE_GET_ROOM_USERS";
	public static final String MAIN_ACTION_ON_FINISHED_GET_ROOM_USERS_FAIL = "MAIN_ACTION_ON_FINISHED_GET_ROOM_USERS_FAIL";
	public static final String MAIN_ACTION_ON_FINISHED_GET_ROOM_USERS_SUCCESS = "MAIN_ACTION_ON_FINISHED_GET_ROOM_USERS_SUCCESS";

	public static final String MAIN_ACTION_ON_USER_ENTERED_ROOM = "MAIN_ACTION_ON_USER_ENTERED_ROOM";
	public static final String MAIN_ACTION_ON_USER_LEFT_ROOM = "MAIN_ACTION_ON_USER_LEFT_ROOM";

	public static final String MAIN_ACTION_ON_PRE_LOG_OUT = "MAIN_ACTION_ON_PRE_LOG_OUT";
	public static final String MAIN_ACTION_ON_FINISHED_LOG_OUT = "MAIN_ACTION_ON_FINISHED_LOG_OUT";

	public static final String MAIN_ACTION_ON_PRE_GET_USER_BY_IDS = "MAIN_ACTION_ON_PRE_GET_USER_BY_IDS";
	public static final String MAIN_ACTION_ON_FINISHED_GET_USER_BY_IDS_FAIL = "MAIN_ACTION_ON_FINISHED_GET_USER_BY_IDS_FAIL";
	public static final String MAIN_ACTION_ON_FINISHED_GET_USER_BY_IDS_SUCCESS = "MAIN_ACTION_ON_FINISHED_GET_USER_BY_IDS_SUCCESS";
	public static final String MAIN_ACTION_UPDATE_MESSAGES_IN_CHAT_PRIVATE = "MAIN_ACTION_UPDATE_MESSAGES_IN_CHAT_PRIVATE";

	// ACTION UI CHAT PRIVATE

	private static ChatService mChatService;
	private static boolean isSetupDone = true;
	// private Context mContext;

	// QuickBlox
	// KEY
	private static final String APP_ID = "16538";
	private static final String AUTH_KEY = "JBeaqLtX856UQet";
	private static final String AUTH_SECRET = "wQCSrzcJuGrT-4R";

	private static QBUser qbUser = null;
	private SmackAndroid smackAndroid;
	private final String PASSWORD_DEFAULT = "abcd123456";
	private final String USER_EXIST = "login has already been taken";
	private final String NOT_REGISTER = "Unauthorized";
	private final String HAVE_LOGGED = "already logged";
	private LocalBroadcastManager broadcaster;
	public static QBPrivateChat chat = null;
	private static QBChatRoom chatRoom;

	private String name;
	private String status;

	private NetworkReceiver networkReceiver;
	private NotificationManager notificationManager;
	private NotificationCompat.Builder builder;
	private Bitmap stub;

	// AUTO CHAT
	private final String AUTO_CHAT_KEY = "a1ffed7f-fa53-4488-83d8-e7cd9ea8448c";
	private MessageContent autoMessageContent;

	public static ChatService getInstance() {
		// if (mChatService == null) {
		// mChatService = new ChatService();
		// }
		return mChatService;
	}

	public void setUpChatService() {
		KiraGameLog.d("setUpChatService");
		getLastAutoMessageContent();
		notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		builder = new NotificationCompat.Builder(this);
		AQuery aq = new AQuery(this);
		stub = aq.getCachedImage(R.drawable.ic_no_avatar);
		generateDeviceID();
		broadcaster = LocalBroadcastManager.getInstance(this);
		getInfo();
		// setUpServer();
	}

	public void getInfo() {
		this.name = DataManager.getInstance(this).getUserName();
		this.status = DataManager.getInstance(this).getUserStatus();
	}

	// public QBUser getQbUser() {
	// return qbUser;
	// }
	//
	// public void setQbUser(QBUser qbUser) {
	// ChatService.qbUser = qbUser;
	// }

	@Override
	public void onCreate() {
		KiraGameLog.d("----------- ChatService onCreate() ------------");
		super.onCreate();
		mChatService = this;
		setUpChatService();
		networkReceiver = new NetworkReceiver();
		networkReceiver.setOnNetworkListener(new OnNetworkListener() {

			@Override
			public void onOnline() {
				// notifyConnectionOnline();
				setUpServer();
			}

			@Override
			public void onOffine() {
				notifyConnectionOffline();
			}
		});
		this.registerReceiver(networkReceiver, new IntentFilter(
				ConnectivityManager.CONNECTIVITY_ACTION));

	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		return START_STICKY;
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	private void generateDeviceID() {
		if (DataManager.getInstance(this).getDeviceID() == null) {
			String deviceId;
			final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
			if (mTelephony.getDeviceId() != null) {
				deviceId = mTelephony.getDeviceId(); // *** use for mobiles
			} else {
				deviceId = Settings.Secure.getString(getContentResolver(),
						Settings.Secure.ANDROID_ID); // *** use for tablets
			}

			// String android_id = Secure.getString(this.getContentResolver(),
			// Secure.ANDROID_ID);
			DataManager.getInstance(this).setDeviceID(deviceId);
		}
	}

	public void setUpServer() {
		if (!isSetupDone) {
			return;
		}
		callBackOnPreSetupServer();
		KiraGameLog.d("Checking quickblox setup...");
		smackAndroid = SmackAndroid.init(this);
		QBSettings.getInstance().fastConfigInit(APP_ID, AUTH_KEY, AUTH_SECRET);
		QBAuth.createSession(new QBCallback() {

			@Override
			public void onComplete(Result result, Object arg1) {
			}

			@Override
			public void onComplete(Result result) {
				if (result.isSuccess()) {
					KiraGameLog.d("Quickblox setup successful!");
					loginQuickblox();
				} else {
					KiraGameLog
							.d("Quickblox setup Error(s) occurred. Look into DDMS log for details, "
									+ "please. Errors: " + result.getErrors());
					if (result.getErrors().size() > 0) {
						callBackOnFinishedSetupServer("Error! "
								+ result.getErrors().get(0));
					} else {
						callBackOnFinishedSetupServer("Error! Please try again!");
					}

				}
			}
		});
	}

	private void loginQuickblox() {
		KiraGameLog.d("Login Quickblox...");
		qbUser = new QBUser(DataManager.getInstance(this).getDeviceID(),
				PASSWORD_DEFAULT);
		QBUsers.signIn(qbUser, new QBCallback() {

			@Override
			public void onComplete(Result arg0, Object arg1) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onComplete(Result result) {
				if (result.isSuccess()) {
					// ((App)getApplication()).setQbUser(qbUser);
					QBChatService.getInstance().loginWithUser(qbUser,
							new SessionCallback() {
								@Override
								public void onLoginSuccess() {
									KiraGameLog.d("Login Success...");
									setUpChatConnection();
								}

								@Override
								public void onLoginError(String error) {
									KiraGameLog.d("Login Error " + error);
									if (error.contains(HAVE_LOGGED)) {
										setUpChatConnection();
									} else {
										callBackOnFinishedSetupServer("Login Error "
												+ error);
									}

								}

							});
				} else {
					KiraGameLog
							.d("Login Error(s) occurred. Look into DDMS log for details, "
									+ "please. Errors: " + result.getErrors());
					if (result.getErrors().get(0).equals(NOT_REGISTER)) {
						KiraGameLog.d("User not exist... Register now! ");
						registerQuickblox();
					} else {
						callBackOnFinishedSetupServer("Sign in error: "
								+ result.getErrors().get(0));
					}
				}
			}
		});
	}

	protected void registerQuickblox() {
		qbUser = new QBUser(DataManager.getInstance(this).getDeviceID(),
				PASSWORD_DEFAULT);

		UserInfo user = new UserInfo();
		user.setStatus(status);
		qbUser.setWebsite(user.toJson());
		qbUser.setFullName(name);
		qbUser.setOldPassword(PASSWORD_DEFAULT);

		QBUsers.signUpSignInTask(qbUser, new QBCallback() {

			@Override
			public void onComplete(Result arg0, Object arg1) {

			}

			@Override
			public void onComplete(Result result) {
				if (result.isSuccess()) {
					QBChatService.getInstance().loginWithUser(qbUser,
							new SessionCallback() {
								@Override
								public void onLoginSuccess() {
									KiraGameLog.d("Login Success...");
									setUpChatConnection();
								}

								@Override
								public void onLoginError(String error) {
									KiraGameLog.d("Login Error " + error);
									if (error.contains(HAVE_LOGGED)) {
										setUpChatConnection();
									} else {
										callBackOnFinishedSetupServer("Login Error "
												+ error);
									}
								}
							});
				} else {
					KiraGameLog
							.d("SignIn Error(s) occurred. Look into DDMS log for details, "
									+ "please. Errors: " + result.getErrors());
					callBackOnFinishedSetupServer("Sign In Error: "
							+ result.getErrors());
				}
			}
		});
	}

	ConnectionListener connectionListener = new ConnectionListener() {

		@Override
		public void reconnectionSuccessful() {
			KiraGameLog.d("reconnection Successful!");
		}

		@Override
		public void reconnectionFailed(Exception arg0) {
			KiraGameLog.d("reconnection Failed");
		}

		@Override
		public void reconnectingIn(int arg0) {
			KiraGameLog.d("reconnecting In");
		}

		@Override
		public void connectionClosedOnError(Exception arg0) {
			KiraGameLog.d("connection Closed On Error");
		}

		@Override
		public void connectionClosed() {
			KiraGameLog.d("connection Closed");
		}
	};

	private void setUpChatConnection() {
		KiraGameLog.d("current userID is " + qbUser.getId());

		DataManager.getInstance(this).setUserID(qbUser.getId());
		// menuFragment.showUserID();
		QBChatService.getInstance().startAutoSendPresence(30);
		QBChatService.getInstance().addConnectionListener(connectionListener);
		setUpChatPrivate();
		callBackOnFinishedSetupServer(null);
	}

	// CHAT PRAVITE

	private void setUpChatPrivate() {
		chat = QBChatService.getInstance().createChat();
		chat.addChatMessageListener(chatPrivateMessageListener);
	}

	ChatMessageListener chatPrivateMessageListener = new ChatMessageListener() {

		@Override
		public void processMessage(Message message) {
			String content = message.getBody();
			String sendTo = message.getFrom().split("-")[0];
			String currentChatID = DataManager.getInstance(ChatService.this)
					.getCurrentChatUserId();
			if (currentChatID != null && currentChatID.equals(sendTo)) {
				updateMessagesInChatActivity(content);
			} else {
				updateMessagesInMessageFragment(content);
			}
			if (DataManager.getInstance(ChatService.this).isShowNotify()) {
				showNotify(content);
			}
			MessagesDataManager.getInstance(ChatService.this).insertMessage(
					sendTo, MessageContent.fromJsonToMessageContent(content));
		}

		@Override
		public boolean accept(Message.Type messageType) {
			switch (messageType) {
			case chat:
				return true;
			default:
				return false;
			}
		}
	};

	public void sendMessage(int to, String message, MsgType msgType) {
		if (chat == null) {
			return;
		}
		try {
			MessageContent msg = new MessageContent();
			msg.setFromUserID(DataManager.getInstance(this).getUserID());
			msg.setName(DataManager.getInstance(this).getUserName());
			msg.setMsgType(msgType);
			msg.setContent(message);
			msg.setAvartar(DataManager.getInstance(this).getUserAvatar());

			// If this user is auto chat
			if (autoMessageContent.getFromUserID().equals(to)) {
				sendAutoChat(message, true);
			} else {
				// else not auto chat
				chat.sendMessage(to, msg.toJson());
			}
			updateMessagesInChatActivity(msg.toJson());
			MessagesDataManager.getInstance(ChatService.this).insertMessage(
					Integer.toString(to), msg);
		} catch (XMPPException e) {
			KiraGameLog.d("send message fail: " + e.getMessage());
			e.printStackTrace();
		}
	}

	public void leaveChat() {
		if (chat == null) {
			return;
		}
		chat.removeChatMessageListener(chatPrivateMessageListener);
	}

	// AUTO CHAT
	public void randomAutoMessageContent() {
		Random r = new Random();
		int random = r.nextInt(Common.listNameAuto.length);
		DataManager.getInstance(this).setLastAutoUserIndex(random);
		autoMessageContent = new MessageContent();
		autoMessageContent.setAvartar(null);
		autoMessageContent.setContent("");
		autoMessageContent.setFromUserID(Common.listUserIDAuto[random]);
		autoMessageContent.setMsgType(MsgType.TEXT);
		autoMessageContent.setName(Common.listNameAuto[random]);
	}

	private void getLastAutoMessageContent() {
		int index = DataManager.getInstance(this).getLastAutoUserIndex();
		autoMessageContent = new MessageContent();
		autoMessageContent.setAvartar(null);
		autoMessageContent.setContent("");
		autoMessageContent.setFromUserID(Common.listUserIDAuto[index]);
		autoMessageContent.setMsgType(MsgType.TEXT);
		autoMessageContent.setName(Common.listNameAuto[index]);
	}

	public void sendAutoChat(String msg, boolean isRandomTime) {
		String lc = "en";
		String text = null;
		try {
			text = URLEncoder.encode(msg, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return;
		}
		double ft = 0.0;
		String url = "http://api.simsimi.com/request.p?key=" + AUTO_CHAT_KEY
				+ "&lc=" + lc + "&ft=" + ft + "&text=" + text;
		final DefaultGetTask task = new DefaultGetTask(url);
		task.setOnGetTaskListener(new onGetTaskListener() {

			@Override
			public void onPreExecute() {
				KiraGameLog.d("send request to autochat");
			}

			@Override
			public void onFailed(String error) {
				KiraGameLog.d("autochat respone fail");
			}

			@Override
			public void onCompleted(String result) {
				KiraGameLog.d("autochat respone  success " + result);
				AutoChatResponse autoChatResponse;
				try {
					autoChatResponse = AutoChatResponse
							.fromJsonToAutoChatResponse(result);
				} catch (Exception e) {
					e.printStackTrace();
					return;
				}
				if (autoChatResponse == null
						|| !autoChatResponse.getResult().equals(100)) {
					return;
				}
				String respone = autoChatResponse.getResponse();
				autoMessageContent.setContent(respone);
				KiraGameLog.d("AutoReply from " + autoMessageContent.getName()
						+ "-" + autoMessageContent.getFromUserID() + " : "
						+ autoMessageContent.getContent());
				String sendTo = Integer.toString(autoMessageContent
						.getFromUserID());
				String content = autoMessageContent.toJson();

				String currentChatID = DataManager
						.getInstance(ChatService.this).getCurrentChatUserId();
				if (currentChatID != null && currentChatID.equals(sendTo)) {
					updateMessagesInChatActivity(content);
				} else {
					updateMessagesInMessageFragment(content);
				}
				if (DataManager.getInstance(ChatService.this).isShowNotify()) {
					showNotify(content);
				}
				MessagesDataManager.getInstance(ChatService.this)
						.insertMessage(
								sendTo,
								MessageContent
										.fromJsonToMessageContent(content));
			}
		});
		if (isRandomTime) {
			long time[] = { 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500,
					5000, 6000, 7000, 8000, 9000, 10000 };
			Random r = new Random();
			int random = r.nextInt(time.length);
			new CountDownTimer(time[random], 1000) {
				@Override
				public void onTick(long millisUntilFinished) {

				}

				@Override
				public void onFinish() {
					Utils.execute(task);
				}
			}.start();
		} else {
			Utils.execute(task);
		}

	}

	// CHAT ROOM
	public void sendMessageChatRoom(String message, MsgType msgType) {
		if (chatRoom == null) {
			return;
		}
		try {
			MessageContent msg = new MessageContent();
			msg.setFromUserID(DataManager.getInstance(this).getUserID());
			msg.setName(DataManager.getInstance(this).getUserName());
			msg.setContent(message);
			msg.setMsgType(msgType);
			msg.setAvartar(DataManager.getInstance(this).getUserAvatar());
			chatRoom.sendMessage(msg.toJson());
		} catch (XMPPException e) {
			KiraGameLog.d("send message to chat room fail: " + e.getMessage());
			e.printStackTrace();
		}
	}

	public void joinroom(String roomID) {
		KiraGameLog.d("Room joining...");
		callBackOnPreJoinRoom();
		leaveRoom();
		QBChatService.getInstance().joinRoom(roomID, this);
	}

	public void getUserOnlineInRoom(int page, int size) {
		callBackOnPreGetRoomUser();
		try {
			Collection<String> roomUsers = chatRoom.getOnlineRoomUsers();
			KiraGameLog.d("User online in room is " + roomUsers.size());
			List<Integer> usersIds = new ArrayList<Integer>();
			for (String string : roomUsers) {
				KiraGameLog.d("user in room " + string);
				usersIds.add(Integer.parseInt(string));
			}

			QBPagedRequestBuilder pagedRequestBuilder = new QBPagedRequestBuilder();
			pagedRequestBuilder.setPage(page);
			pagedRequestBuilder.setPerPage(size);

			QBUsers.getUsersByIDs(usersIds, pagedRequestBuilder,
					new QBCallbackImpl() {
						@Override
						public void onComplete(Result result) {
							if (result.isSuccess()) {
								QBUserPagedResult usersResult = (QBUserPagedResult) result;
								ArrayList<QBUser> users = usersResult
										.getUsers();
								List<User> xchatUsers = new ArrayList<User>();
								for (QBUser user : users) {
									User xchatUser = new User();
									xchatUser.setUserID(user.getId());
									xchatUser.setName(user.getFullName());
									xchatUser
											.setUserInfo(getUserInfoFromQBWebsite(user
													.getWebsite()));
									xchatUsers.add(xchatUser);
								}
								callBackOnFinishedGetRoomUserSuccess(User
										.toJsonArray(xchatUsers));
							} else {
								KiraGameLog.d("Get user in room error: "
										+ result.getErrors().toString());
								callBackOnFinishedGetRoomUserFail("Get user in room error: "
										+ result.getErrors().toString());
							}
						}
					});
		} catch (XMPPException e) {
			callBackOnFinishedGetRoomUserFail("Get user in room error!");
			KiraGameLog.d("Get user in room error! ");
			e.printStackTrace();
		}
	}

	public void getUserByIds(Collection<String> userIDs, int page, int size) {
		callBackOnPreGetUserByIDs();
		List<Integer> mUserIds = new ArrayList<Integer>();
		for (String string : userIDs) {
			mUserIds.add(Integer.parseInt(string));
		}

		QBPagedRequestBuilder pagedRequestBuilder = new QBPagedRequestBuilder();
		pagedRequestBuilder.setPage(page);
		pagedRequestBuilder.setPerPage(size);

		QBUsers.getUsersByIDs(mUserIds, pagedRequestBuilder,
				new QBCallbackImpl() {
					@Override
					public void onComplete(Result result) {
						if (result.isSuccess()) {
							QBUserPagedResult usersResult = (QBUserPagedResult) result;
							ArrayList<QBUser> users = usersResult.getUsers();
							List<User> xchatUsers = new ArrayList<User>();
							for (QBUser user : users) {
								User xchatUser = new User();
								xchatUser.setUserID(user.getId());
								xchatUser.setName(user.getFullName());
								xchatUser
										.setUserInfo(getUserInfoFromQBWebsite(user
												.getWebsite()));
								xchatUsers.add(xchatUser);
							}
							callBackOnFinishedGetUserByIDsSuccess(User
									.toJsonArray(xchatUsers));
						} else {
							KiraGameLog.d("Get user in room error: "
									+ result.getErrors().toString());
							callBackOnFinishedGetUserByIDsFail("Get user by ids error: "
									+ result.getErrors().toString());
						}
					}
				});
	}

	@Override
	public void onCreatedRoom(QBChatRoom room) {
		KiraGameLog.d("JoinRoom onCreatedRoom");
		chatRoom = room;
		chatRoom.addMessageListener(chatRoomMessageListener);
		callBackOnFinishedJoinRoom(null);
	}

	@Override
	public void onError(String error) {
		KiraGameLog.d("JoinRoom onError " + error);
		callBackOnFinishedJoinRoom(error);
	}

	@Override
	public void onJoinedRoom(QBChatRoom room) {
		KiraGameLog.d("JoinRoom onJoinedRoom");
		chatRoom = room;
		chatRoom.addMessageListener(chatRoomMessageListener);
		callBackOnFinishedJoinRoom(null);
	}

	public void setEnterLeftRoomListener() {
		chatRoom.addParticipantListener(participantListener);
	}

	PacketListener participantListener = new PacketListener() {

		@Override
		public void processPacket(Packet packet) {
			Presence presence = (Presence) packet;
			String userID = presence.getFrom().split("/")[1];
			if (presence.getType() == Presence.Type.available) {
				// user entered the room
				KiraGameLog.d("User " + userID + " entered room");
				callBackOnUserEnteredRoom(userID);
			} else if (presence.getType() == Presence.Type.unavailable) {
				// user left the room
				KiraGameLog.d("User " + userID + " has left room");
				callBackOnUserLeftRoom(userID);
			}
			// Collection<String> roomUsers = chatRoom.getOnlineRoomUsers();
		}
	};

	ChatMessageListener chatRoomMessageListener = new ChatMessageListener() {

		@Override
		public boolean accept(Message.Type messageType) {
			switch (messageType) {
			case groupchat:
				return true;
			default:
				return false;
			}
		}

		@Override
		public void processMessage(Message message) {
			// MessageContent msg = new MessageContent();
			// String sender = QBChatUtils.parseRoomOccupant(message.getFrom());
			// msg.setName(sender);
			String content = message.getBody();
			updateMessageInChatRoomFragment(content);
			// Date time = QBChatUtils.parseTime(message);
			// if (time == null) {
			// time = Calendar.getInstance().getTime();
			// }
			// Show message
			// String sender = QBChatUtils.parseRoomOccupant(message.getFrom());
			// QBUser qbUser = ((App)
			// (chatActivity.getApplication())).getQbUser();
			// if (sender.equals(qbUser.getFullName()) ||
			// sender.equals(qbUser.getId().toString())) {
			// chatActivity.showMessage(new ChatMessage(message.getBody(), "me",
			// time, false));
			// } else {
			// chatActivity.showMessage(new ChatMessage(message.getBody(),
			// sender, time, true));
			// }

		}
	};

	public void leaveRoom() {
		if (chatRoom == null) {
			return;
		}
		try {
			chatRoom.removeMessageListener(chatRoomMessageListener);
			QBChatService.getInstance().leaveRoom(chatRoom);
			chatRoom = null;
		} catch (Exception e) {
			KiraGameLog.d("Leave room error!");
			chatRoom = null;
			e.printStackTrace();
		}
	}

	// PROFILE
	public void updateProfile(final String name, final String status,
			final String avatarURL) {
		callBackOnPreUpdateProfile();
		if (name != null) {
			qbUser.setFullName(name);
		} else {
			qbUser.setFullName(DataManager.getInstance(this).getUserName());
		}

		final UserInfo user = new UserInfo();

		if (status != null) {
			user.setStatus(status);
		} else {
			user.setStatus(DataManager.getInstance(this).getUserStatus());
		}

		if (avatarURL != null) {
			user.setAvatarURL(avatarURL);
		} else {
			user.setAvatarURL(DataManager.getInstance(this).getUserAvatar());
		}
		qbUser.setWebsite(user.toJson());
		qbUser.setOldPassword(PASSWORD_DEFAULT);
		QBUsers.updateUser(qbUser, new QBCallback() {

			@Override
			public void onComplete(Result arg0, Object arg1) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onComplete(Result result) {
				if (result.isSuccess()) {
					KiraGameLog.d("User was edited successful");
					DataManager.getInstance(ChatService.this).setUserName(
							qbUser.getFullName());
					DataManager.getInstance(ChatService.this).setUserStatus(
							user.getStatus());
					DataManager.getInstance(ChatService.this).setUserAvatar(
							user.getAvatarURL());
					callBackOnFinishedUpdateProfile(null);
				} else {
					KiraGameLog.d("Errors " + result.getErrors().toString());
					callBackOnFinishedUpdateProfile("Update Profile error: "
							+ result.getErrors().toString());
				}
			}
		});
	}

	@Override
	public void onDestroy() {
		KiraGameLog.d("----------- ChatService onDestroy() ------------");
		if (smackAndroid != null) {
			try {
				smackAndroid.onDestroy();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		leaveRoom();
		leaveChat();
		KiraGameLog.d("chat service stop!");
		unregisterReceiver(networkReceiver);
		QBChatService.getInstance().stopAutoSendPresence();
		QBChatService.getInstance()
				.removeConnectionListener(connectionListener);
		MessagesDataManager.getInstance(this).deleteAllMessage();
		MessagesDataManager.getInstance(this).deleteHistoryMessageUnMarkFriend();
		QBUsers.signOut(new QBCallbackImpl() {
			@Override
			public void onComplete(Result result) {
				if (result.isSuccess()) {
					callBackOnFinishedLogOut(null);
				} else {
					KiraGameLog.d("Sign out error: "
							+ result.getErrors().get(0));
					callBackOnFinishedLogOut(result.getErrors().get(0));
				}

			}
		});
		mChatService = null;
		super.onDestroy();
	}

	public void logOut() {
		callBackOnPreLogOut();
		stopSelf();
	}

	protected void notifyConnectionOffline() {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_NOTIFY_CONNECTION_OFFLINE, null);
	}

	protected void notifyConnectionOnline() {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_NOTIFY_CONNECTION_ONLINE, null);
	}

	private void updateMessagesInMessageFragment(String content) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_UPDATE_MESSAGES_IN_MESSAGE_FRAGMENT,
				content);
	}

	private void updateMessagesInChatActivity(String content) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_UPDATE_MESSAGES_IN_CHAT_PRIVATE,
				content);
	}

	private void updateMessageInChatRoomFragment(String json) {
		updateUI(UI_NAME_MAIN,
				MAIN_ACTION_UPDATE_MESSAGES_IN_CHAT_ROOM_FRAGMENT, json);
	}

	private void updateUI(String nameUI, String action, String message) {
		Intent intent = null;
		switch (nameUI) {
		case UI_NAME_LOGIN:
			intent = new Intent(BROADCAST_NAME_LOGIN);
			break;
		case UI_NAME_MAIN:
			intent = new Intent(BROADCAST_NAME_MAIN);
			break;
		case UI_NAME_CHAT_PRIVATE:
			intent = new Intent(BROADCAST_NAME_CHAT_PRIVATE);
			break;
		default:
			return;
		}

		intent.putExtra(CONTROL_ACTION, action);
		if (message != null) {
			intent.putExtra(CONTROL_MESSAGE, message);
		}
		broadcaster.sendBroadcast(intent);
	}

	public void release() throws XMPPException {
		if (chat != null) {
			chat.removeChatMessageListener(chatPrivateMessageListener);
		}
		if (chatRoom != null) {
			QBChatService.getInstance().leaveRoom(chatRoom);
			chatRoom.removeMessageListener(chatRoomMessageListener);
		}
	}

	// MAIN CALLBACK

	private void callBackOnPreSetupServer() {
		isSetupDone = false;
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_PRE_SETUP_SERVER, null);
	}

	private void callBackOnFinishedSetupServer(String error) {
		isSetupDone = true;
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_FINISHED_SETUP_SERVER, error);
	}

	private void callBackOnPreUpdateProfile() {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_PRE_UPDATE_PROFILE, null);
	}

	private void callBackOnFinishedUpdateProfile(String error) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_FINISHED_UPDATE_PROFILE, error);
	}

	private void callBackOnPreJoinRoom() {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_PRE_JOIN_ROOM, null);
	}

	private void callBackOnFinishedJoinRoom(String error) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_FINISHED_JOIN_ROOM, error);
	}

	private void callBackOnPreGetRoomUser() {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_PRE_GET_ROOM_USERS, null);
	}

	private void callBackOnFinishedGetRoomUserFail(String error) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_FINISHED_GET_ROOM_USERS_FAIL,
				error);
	}

	private void callBackOnFinishedGetRoomUserSuccess(String data) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_FINISHED_GET_ROOM_USERS_SUCCESS,
				data);
	}

	private void callBackOnUserEnteredRoom(String userID) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_USER_ENTERED_ROOM, userID);
	}

	private void callBackOnUserLeftRoom(String userID) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_USER_LEFT_ROOM, userID);
	}

	private void callBackOnPreLogOut() {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_PRE_LOG_OUT, null);
	}

	private void callBackOnFinishedLogOut(String error) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_FINISHED_LOG_OUT, error);
	}

	protected void callBackOnFinishedGetUserByIDsFail(String error) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_FINISHED_GET_USER_BY_IDS_FAIL,
				error);
	}

	protected void callBackOnFinishedGetUserByIDsSuccess(String data) {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_FINISHED_GET_USER_BY_IDS_SUCCESS,
				data);
	}

	private void callBackOnPreGetUserByIDs() {
		updateUI(UI_NAME_MAIN, MAIN_ACTION_ON_PRE_GET_USER_BY_IDS, null);
	}

	// UTILS

	public boolean isNewProfile(String name, String status) {
		if (qbUser == null) {
			return false;
		}
		UserInfo user = getUserInfoFromQBWebsite(qbUser.getWebsite());
		if (name != null && name.equals(qbUser.getFullName()) && status != null
				&& status.equals(user.getStatus())) {
			return false;
		}
		return true;
	}

	public UserInfo getUserInfoFromQBWebsite(String website) {
		String info = website.replace("http://", "");
		UserInfo user = UserInfo.fromJsonToUserInfo(info);
		return user;
	}

	private synchronized void showNotify(String content) {
		if (!DataManager.getInstance(this).getNotificationSetting()) {
			return;
		}
		MessageContent msgContent = MessageContent
				.fromJsonToMessageContent(content);
		try {
			final String messageContent = msgContent.getContent();
			final long when = System.currentTimeMillis();
			final String title = msgContent.getName();

			Intent notificationIntent = new Intent(this, MainActivity.class);
			// notificationIntent.putExtra(Common.ExtraKey.USER_NAME,
			// msgContent.getName());
			// notificationIntent.putExtra(Common.ExtraKey.USER_ID,
			// msgContent.getFromUserID());
			DataManager.getInstance(this).setNotifyUserId(
					msgContent.getFromUserID());
			DataManager.getInstance(this).setNotifyUserName(
					msgContent.getName());
			notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
					| Intent.FLAG_ACTIVITY_SINGLE_TOP);
			// notificationIntent.setAction(Intent.ACTION_MAIN);
			// notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
			final PendingIntent intent = PendingIntent.getActivity(this, 0,
					notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

			if (msgContent.getAvartar() != null) {
				AQuery aq = new AQuery(this);
				aq.id(new ImageView(this)).image(msgContent.getAvartar(), true,
						true, 50, 0, new BitmapAjaxCallback() {
							@Override
							public void callback(String url, ImageView iv,
									Bitmap bm, AjaxStatus status) {
								if (bm != null) {
									showNotification(messageContent, bm, title,
											when, intent, 1);
								} else {
									showNotification(messageContent, null,
											title, when, intent, 1);
								}
							}
						});
			} else {
				showNotification(messageContent, null, title, when, intent, 1);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public synchronized void showNotification(String message, Bitmap icon,
			String title, long when, PendingIntent intent, int id) {
		KiraGameLog.d(String.format("show notication message: %s, title: %s",
				message, title));
		builder.setContentText(message);
		builder.setSmallIcon(R.drawable.ic_launcher);
		builder.setLights(0xFFFF8800, 200, 200);
		builder.setWhen(when);
		if (icon != null) {
			builder.setLargeIcon(icon);
		} else {
			builder.setLargeIcon(stub);
		}
		if (title != null) {
			builder.setContentTitle(title);
		}
		if (intent != null) {
			builder.setContentIntent(intent);
		}
		if (DataManager.getInstance(this).getVibrationSetting()) {
			long[] pattern = { 0, 100 };
			builder.setVibrate(pattern);
		}
		if (DataManager.getInstance(this).getSoundSetting()) {
			builder.setSound(RingtoneManager
					.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
		} else {
			builder.setSound(null);
		}
		builder.setAutoCancel(true);
		Notification notification = builder.build();
		notificationManager.notify(id, notification);
	}

	public boolean isLogin() {
		return QBChatService.getInstance().isLoggedIn();
	}

}
